package com.wp.config;

import com.alibaba.fastjson.JSON;
import com.wp.filter.MyFilter;
import com.wp.service.UserService;
import com.wp.service.impl.UserServiceImpl;
import com.wp.util.JwtUtil;
import com.wp.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.PrintWriter;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: WangPeng
 * @createTime: 2023/01/03 11:21
 * @description:
 * @version: v1.0
 */
@Configuration
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserService userService;

    @Autowired
    private MyFilter myFilter;

    //定义密码加密方式
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    //指定账户和密码的来源
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    //设置security认证的规则
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilterBefore(myFilter, UsernamePasswordAuthenticationFilter.class);
        //指定登录表单的规则
        http.formLogin()
                //这个路径必须和登录表单的提交路径一致。
                .loginProcessingUrl("/login")

                //设置自定义登录界面
                //.loginPage("/login.html")
                //登录成功后转发的路径
                //.successForwardUrl("/main")

                //登录成功后进入处理的业务代码
                .successHandler(successHandler())
                //用户登录失败后处理的业务代码
                .failureHandler(failureHandler())
                .permitAll();

        //没有权限时跳转的路径
        //http.exceptionHandling().accessDeniedPage("/403.html");
        http.exceptionHandling().accessDeniedHandler(deniedHandler());

        //禁用跨站伪造请求,不使用csrf过滤器。
        http.csrf().disable();

        //允许跨域
        http.cors();

        //设置其他路径需要认证后才能访问
        http.authorizeRequests().anyRequest().authenticated();

    }

    private AuthenticationSuccessHandler successHandler(){
        return  (request, response, authentication) -> {
            //设置编码
            response.setContentType("json/application;charset=utf-8");
            //登录成功的业务代码.---servlet可以通过该对象输出json数据。
            PrintWriter writer = response.getWriter();
            //账户和该账户具有的权限放入到token令牌中
            User principal = (User) authentication.getPrincipal();
            //获取用户名
            String username = principal.getUsername();
            //获取用户对应的权限
            Collection<GrantedAuthority> authorities = principal.getAuthorities();
            //将权限转换为List集合类型
            List<String> list = authorities.stream().map(item -> item.getAuthority()).collect(Collectors.toList());

            //将用户名和该用户拥有的权限封装到map中
            Map<String, Object> map = new HashMap<>();
            map.put("username",username);
            map.put("authorities",list);

            //将用户信息放入token中
            String token = JwtUtil.createToken(map);

            Result result = new Result(200, "登录成功",token);
            String jsonString = JSON.toJSONString(result);
            writer.print(jsonString);
            writer.flush();
            writer.close();
        };
    }

    private AuthenticationFailureHandler failureHandler(){
        return (request ,response ,authenticationException)->{
            //设置编码
            response.setContentType("json/application;charset=utf-8");
            //登录成功的业务代码.---servlet可以通过该对象输出json数据。
            PrintWriter writer = response.getWriter();

            Result result=new Result(500,"账户或密码错误");
            String jsonString = JSON.toJSONString(result);
            writer.print(jsonString);
            writer.flush();
            writer.close();
        };
    }

    private AccessDeniedHandler deniedHandler(){
        return (request ,response ,authenticationException)->{
            //设置编码
            response.setContentType("json/application;charset=utf-8");
            //登录成功的业务代码.---servlet可以通过该对象输出json数据。
            PrintWriter writer = response.getWriter();
            Result result=new Result(403,"权限不足");
            String jsonString = JSON.toJSONString(result);
            writer.print(jsonString);
            writer.flush();
            writer.close();
        };
    }
}
